use std::collections::HashMap;
use std::{env};
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::Path;
use std::string::ToString;

const CONFIGURATION_FILE_PATH_COMMAND    : &str = "configFile";
const CONFIGURATION_FILE_NAME            : &str = "tractor.conf";
const CONFIGURATION_SPLIT                : &str = "=";

const DEFAULT_CONFIGURATION_FILE_PATH    : &str = "./";
#[derive(Debug)]
pub struct Config {
     configs_in_command_map      :       HashMap<String,String>,  //启动时命令行中的配置
     configs_in_file_map         :       HashMap<String,String>,  //配置文件中的的配置
}

/// 命令参数：  ‘=’连接值， 命令=值， 多个命令使用空格隔开。
/// command_name1=command_value1 command_name2=command_value2
impl Config {

    pub fn new() -> Config {
        Config {
            configs_in_command_map: Default::default(),
            configs_in_file_map: Default::default(),
        }
    }
    pub fn init() ->Config{
        let mut config = Config::new();
        config.read_configs_from_command();
        config.read_configs_from_file();
        config
    }

    /// the value in command is first
    pub fn get_value_for(&self, key: &str) -> Option<&String> {
        let option = self.configs_in_command_map.get(key);
        if option.is_none() {
            self.configs_in_file_map.get(key)
        }else {
            option
        }
    }

    pub fn get_value_u16(&self, key:&str) ->Option<u16> {
        let option = self.get_value_for(key);
        if option.is_some() {
            let value = option.unwrap().parse::<u16>().unwrap();
            Some(value)
        }else {
            Option::None
        }
    }

    pub fn get_value_with_default_usize(&self, key:&str,default:usize) ->usize {
        let option = self.get_value_for(key);
        if option.is_none() {
            default
        }else {
            option.unwrap().parse().unwrap()
        }
    }

    fn read_configs_from_command (&mut self) {
        println!("Start to read configurations from start command...");
        let env_args : Vec<String> = env::args().collect();
        if env_args.is_empty() {
            println!("There is not any configuration in start command.");
        }else {
            let mut iterator =  env_args.iter();
            for arg in iterator.next() {
                if arg.contains("=") {
                   let _arg :Vec<&str> = arg.split(&CONFIGURATION_SPLIT).collect();
                    self.configs_in_command_map.insert(_arg[0].to_string(), _arg[1].to_string());
                }else {
                    //命令不合法
                    eprintln!("The arg {} is invalid", arg);
                }
            }
        }
        println!("End to read configurations from start command...");
        println!("The args in command: {:?}", self.configs_in_command_map);

    }

    /// 配置文件中的配置格式：configuration=value
    /// 例如配置端口号： port=8080
    fn read_configs_from_file(&mut self)  {
        println!("Start to read configurations from start command...");
        let mut configuration_file_path = DEFAULT_CONFIGURATION_FILE_PATH;
        if self.configs_in_file_map.is_empty(){
            if !self.configs_in_command_map.is_empty() {
                configuration_file_path = self.configs_in_command_map.get(&*CONFIGURATION_FILE_PATH_COMMAND).unwrap().as_str();
            }
        }
        //read the configuration in the path
        let configuraton_path_name = configuration_file_path.to_string()+CONFIGURATION_FILE_NAME;
        let path = Path::new(configuraton_path_name.as_str());
        if path.exists(){
            let mut config = String::new();
            let file  = File::open(path).expect("Can not open the configuration file directory.");
            let mut buf_reader = BufReader::new(file);
            if buf_reader.read_line(&mut config).unwrap()>0 {
                let config_item :Vec<&str>= config.split(&CONFIGURATION_SPLIT).collect();
                self.configs_in_file_map.insert(config_item[0].to_string(), config_item[1].to_string());
            }

        }else {
            //panic!("Can not find the configuration file in the directory {}", configuration_file_path);
            eprintln!("Can not find the configuration file in the directory {}", configuration_file_path);
        };
    }
}

